package com.gitee.tianchaohongyu.service;

import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.NetClient;
import io.vertx.core.net.NetServer;
import io.vertx.core.net.NetSocket;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.Nullable;

import java.util.LinkedList;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 远程服务器
 */
@Slf4j
public class RemoteServer {

    public static String HANDSHAKE_SUCCESS = "@!@连接成功。";
    private static Pattern pattern = Pattern.compile("^([0-9a-zA-Z\\u4e00-\\u9fa5.-]+):(\\d+)/(\\S+)$");

    String password;
    int serverPort;

    /**
     * 构造服务器
     *
     * @param serverPort 服务器端口
     * @param password   密码
     */
    public RemoteServer(int serverPort, String password) {
        this.password = password;
        this.serverPort = serverPort;
    }


    /**
     * 启动服务
     */
    public void start() {
        Vertx vertx = Vertx.vertx();
        NetServer server = vertx.createNetServer();
        server.connectHandler(request -> request.handler(buffer -> {
            String data = buffer.toString();
            Matcher matcher = pattern.matcher(data);
            if (!matcher.find()) {
                request.write("@!@请求参数无法识别。");
                request.close();
            } else if (!Objects.equals(matcher.group(3), password)) {
                request.write("@!@密码错误。");
                request.close();
            } else {
                new AgentHandler(vertx, request, matcher.group(1), Integer.parseInt(matcher.group(2)));
            }
        }));

        // 监听端口
        server.listen(serverPort, event -> {
            if (event.succeeded()) {
                log.info("服务器启动成功");
            } else {
                log.error("服务器启动失败:" + event.cause().getMessage(), event.cause().getMessage());
            }
        });
    }


    /**
     * 控制器
     */
    private static class AgentHandler {

        NetSocket targetSocket = null;
        LinkedList<Buffer> toTargetBuffers = new LinkedList<>();

        public AgentHandler(Vertx vertx, NetSocket request, String targetIp, int targetPort) {
            //连接到目标服务器,并将数据
            NetClient targetServer = vertx.createNetClient();
            targetServer.connect(targetPort, targetIp, target -> {
                if (!target.succeeded()) {
                    toTargetBuffers.clear();
                    request.write("@!@连接目标服务器失败。");
                    request.close();
                } else {
                    request.write(HANDSHAKE_SUCCESS);
                    targetSocket = target.result();
                    forwardToTarget(null);
                    targetSocket.handler(request::write);
                    targetSocket.closeHandler(it -> {
                        request.close();
                        toTargetBuffers.clear();
                    });
                }
            });

            //请求往目标的数据转发
            request.handler(this::forwardToTarget);

            //如果请求连接关闭,则关闭代理连接诶
            request.closeHandler(it -> {
                toTargetBuffers.clear();
                if (targetSocket != null) {
                    targetServer.close();
                }
            });
        }

        /**
         * 转发给目标服务器
         *
         * @param buffer 缓冲数据
         */
        private void forwardToTarget(@Nullable Buffer buffer) {
            if (targetSocket == null && buffer != null) {
                toTargetBuffers.add(buffer);
            } else if (buffer != null) {
                targetSocket.write(buffer);
            }
            while (targetSocket != null && !toTargetBuffers.isEmpty()) {
                targetSocket.write(toTargetBuffers.remove(0));
            }
        }
    }
}
